<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- Use correct character set. -->
    <meta charset="utf-8" />
    <!-- Tell IE to use the latest, best version. -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <title>Hello World!</title>
    <!-- <script src="../Build/Cesium/Cesium.js"></script> -->
    <script src="../Build/CesiumUnminified/Cesium.js"></script>
    <script src="../node_modules/lodash/lodash.min.js"></script>
    <style>
      @import url(../Build/Cesium/Widgets/widgets.css);

      html,
      body,
      #cesiumContainer {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        overflow: hidden;
      }
    </style>
  </head>

  <body>
    <div id="cesiumContainer"></div>
    <script>
      var minimumHeight = 0;
      var DemoTileProvider = function DemoTileProvider() {
        this._quadtree = undefined;
        this._tilingScheme = new Cesium.GeographicTilingScheme();
        this._errorEvent = new Cesium.Event();
        this._levelZeroMaximumError = Cesium.QuadtreeTileProvider.computeDefaultLevelZeroMaximumGeometricError(
          this._tilingScheme
        );
        this.cartographicLimitRectangle = Cesium.Rectangle.clone(
          Cesium.Rectangle.MAX_VALUE
        );
        this._PrimitiveCollection = new Cesium.PrimitiveCollection();
      };
      Object.defineProperties(Cesium, DemoTileProvider.prototype, {
        quadtree: {
          get: function () {
            return this._quadtree;
          },
          set: function (value) {
            this._quadtree = value;
          },
        },
        ready: {
          get: function () {
            return true;
          },
        },
        tilingScheme: {
          get: function () {
            return this._tilingScheme;
          },
        },
        errorEvent: {
          get: function () {
            return this._errorEvent;
          },
        },
      });
      var rectangleIntersectionScratch = new Cesium.Rectangle();
      var cornerPositionsScratch = [
        new Cesium.Cartesian3(),
        new Cesium.Cartesian3(),
        new Cesium.Cartesian3(),
        new Cesium.Cartesian3(),
      ];
      DemoTileProvider.prototype.update = function (frameState) {
        this._quadtree.beginFrame(frameState);
        this._quadtree.render(frameState);
        this._quadtree.endFrame(frameState);
      };
      DemoTileProvider.prototype.initialize = function (frameState) {};
      DemoTileProvider.prototype.beginUpdate = function (frameState) {
        // debugger
        // for (var i = 0; i < this._reTiles.length; i++) {
        //     var tile = this._reTiles[i];
        //     if (this.computeTileVisibility(tile, frameState, null) == Cesium.Visibility.NONE) {
        //         for (var key in frameState.context._pickObjects) {
        //             var obj = frameState.context._pickObjects[key];
        //             if (obj.id.indexOf('z' + tile.level + 'x' + tile.x + 'y' + tile.y + 'n') == 0) {
        //                 delete frameState.context._pickObjects[key];
        //             }
        //         }
        //     }
        // }
      };
      DemoTileProvider.prototype.endUpdate = function (frameState) {};

      DemoTileProvider.prototype.getLevelMaximumGeometricError = function (
        level
      ) {
        return this._levelZeroMaximumError / (1 << level);
      };
      DemoTileProvider.prototype.loadTile = function (frameState, tile) {
        // debugger
        // setTimeout(() => {
        if (tile.state === Cesium.QuadtreeTileLoadState.START) {
          tile.data = {
            lines: [],
            geometryPrimitive: undefined,
          };

          var levelError = this.getLevelMaximumGeometricError(tile.level);
          if (tile.level < 21) {
            // Create random lines at the root level.
            var geometries = [];
            for (var i = 0; i < 125; ++i) {
              var positions = [];
              var firstLongitude = Cesium.Math.lerp(
                tile.rectangle.west,
                tile.rectangle.east,
                Math.random()
              );
              var firstLatitude = Cesium.Math.lerp(
                tile.rectangle.south,
                tile.rectangle.north,
                Math.random()
              );
              var first = Cesium.Cartesian3.fromRadians(
                firstLongitude,
                firstLatitude
              );
              positions.push(first);
              var lastLongitude = Cesium.Math.lerp(
                tile.rectangle.west,
                tile.rectangle.east,
                Math.random()
              );
              var lastLatitude = Cesium.Math.lerp(
                tile.rectangle.south,
                tile.rectangle.north,
                Math.random()
              );
              var last = Cesium.Cartesian3.fromRadians(
                lastLongitude,
                lastLatitude,
                -1000
              );
              positions.push(last);
              var geometry = new Cesium.GeometryInstance({
                geometry: Cesium.BoxGeometry.fromDimensions({
                  dimensions: new Cesium.Cartesian3(
                    Cesium.Math.nextRandomNumber() * 100,
                    Cesium.Math.nextRandomNumber() * 100,
                    Cesium.Math.nextRandomNumber() * 500
                  ),
                }),
                modelMatrix: Cesium.Matrix4.multiplyByTranslation(
                  Cesium.Transforms.eastNorthUpToFixedFrame(last),
                  new Cesium.Cartesian3(0.0, 0.0, 0),
                  new Cesium.Matrix4()
                ),
                //new Cesium.PolylineGeometry({
                //    positions: positions,
                //    vertexFormat: Cesium.PolylineMaterialAppearance.VERTEX_FORMAT
                //})
              });

              geometries.push(geometry);
            }

            // tile.data.geometryPrimitive = new Cesium.Primitive({
            //     geometryInstances: geometries,
            //     appearance: new Cesium.MaterialAppearance({
            //         material: new Cesium.Material({
            //             fabric: {
            //                 type: 'Color',
            //                 uniforms: {
            //                     color: Cesium.Color.fromRandom({ alpha: 1.0 })
            //                 }
            //             }
            //         }),
            //         faceForward: true,
            //         flat: false
            //     }),
            //     shadows: Cesium.ShadowMode.ENABLED
            // });
            tile._minimumHeight = 0;
            tile._maximumHeight = 0;
            var c = new Cesium.Primitive({
              geometryInstances: geometries,
              appearance: new Cesium.MaterialAppearance({
                material: new Cesium.Material({
                  fabric: {
                    type: "Color",
                    uniforms: {
                      color: Cesium.Color.fromRandom({ alpha: 1.0 }),
                    },
                  },
                }),
                faceForward: true,
                flat: false,
              }),
              shadows: Cesium.ShadowMode.ENABLED,
              isUpdateQuad: 1,
            });
            // this._PrimitiveCollection.add(c);
            tile.data.geometryPrimitive = c;
          } else {
            // Add more detail to parent lines at every other level.
            return;
          }
          tile.state = Cesium.QuadtreeTileLoadState.LOADING;
        }

        if (
          tile.state === Cesium.QuadtreeTileLoadState.LOADING &&
          tile.data &&
          tile.data.geometryPrimitive
        ) {
          tile.data.geometryPrimitive.update(frameState, []);
          // tile.data.geometryPrimitive._isUpdateQuad = 1;
          if (tile.data.geometryPrimitive._ready) {
            tile.state = Cesium.QuadtreeTileLoadState.DONE;
            tile.renderable = true;
          }
        }

        // tile.data.tileBoundingRegion = new Cesium.TileBoundingRegion({
        //         computeBoundingVolumes: true,
        //         rectangle: tile.rectangle,
        //         ellipsoid: tile.tilingScheme.ellipsoid,
        //         minimumHeight: 0.0,
        //         maximumHeight: 0.0
        //     });
        // }, 1000);
      };

      DemoTileProvider.prototype.computeTileVisibility = function (
        tile,
        frameState,
        occluders
      ) {
        var distance = this.computeDistanceToTile(tile, frameState);
        tile._distance = distance;

        if (frameState.fog.enabled) {
          if (Cesium.Math.fog(distance, frameState.fog.density) >= 1.0) {
            // Tile is completely in fog so return that it is not visible.
            return Cesium.Visibility.NONE;
          }
        }

        var surfaceTile = tile.data;
        var tileBoundingRegion = surfaceTile.tileBoundingRegion;

        if (surfaceTile.boundingVolumeSourceTile === undefined) {
          // We have no idea where this tile is, so let's just call it partially visible.
          return Cesium.Visibility.PARTIAL;
        }

        var cullingVolume = frameState.cullingVolume;
        var boundingVolume = surfaceTile.orientedBoundingBox;

        if (!boundingVolume && surfaceTile.renderedMesh) {
          boundingVolume = surfaceTile.renderedMesh.boundingSphere3D;
        }

        // Check if the tile is outside the limit area in cartographic space
        surfaceTile.clippedByBoundaries = false;
        var clippedCartographicLimitRectangle = clipRectangleAntimeridian(
          tile.rectangle,
          this.cartographicLimitRectangle
        );
        var areaLimitIntersection = Cesium.Rectangle.simpleIntersection(
          clippedCartographicLimitRectangle,
          tile.rectangle,
          rectangleIntersectionScratch
        );
        if (!areaLimitIntersection) {
          return Cesium.Visibility.NONE;
        }
        if (!Cesium.Rectangle.equals(areaLimitIntersection, tile.rectangle)) {
          surfaceTile.clippedByBoundaries = true;
        }

        if (frameState.mode !== Cesium.SceneMode.SCENE3D) {
          boundingVolume = boundingSphereScratch;
          BoundingSphere.fromRectangleWithHeights2D(
            tile.rectangle,
            frameState.mapProjection,
            tileBoundingRegion.minimumHeight,
            tileBoundingRegion.maximumHeight,
            boundingVolume
          );
          Cartesian3.fromElements(
            boundingVolume.center.z,
            boundingVolume.center.x,
            boundingVolume.center.y,
            boundingVolume.center
          );

          if (
            frameState.mode === SceneMode.MORPHING &&
            surfaceTile.renderedMesh
          ) {
            boundingVolume = BoundingSphere.union(
              surfaceTile.renderedMesh.boundingSphere3D,
              boundingVolume,
              boundingVolume
            );
          }
        }

        if (!boundingVolume) {
          return Cesium.Intersect.INTERSECTING;
        }

        var clippingPlanes = this._clippingPlanes;
        if (clippingPlanes && clippingPlanes.enabled) {
          var planeIntersection = clippingPlanes.computeIntersectionWithBoundingVolume(
            boundingVolume
          );
          tile.isClipped = planeIntersection !== Intersect.INSIDE;
          if (planeIntersection === Cesium.Intersect.OUTSIDE) {
            return Cesium.Visibility.NONE;
          }
        }

        var intersection = cullingVolume.computeVisibility(boundingVolume);
        if (intersection === Cesium.Intersect.OUTSIDE) {
          return Cesium.Visibility.NONE;
        }

        var ortho3D =
          frameState.mode === Cesium.SceneMode.SCENE3D &&
          frameState.camera.frustum instanceof Cesium.OrthographicFrustum;
        if (
          frameState.mode === Cesium.SceneMode.SCENE3D &&
          !ortho3D &&
          occluders
        ) {
          var occludeePointInScaledSpace =
            surfaceTile.occludeePointInScaledSpace;
          if (!occludeePointInScaledSpace) {
            return intersection;
          }

          if (
            occluders.ellipsoid.isScaledSpacePointVisible(
              occludeePointInScaledSpace
            )
          ) {
            return intersection;
          }
          return Cesium.Visibility.NONE;
        }

        return intersection;
      };

      DemoTileProvider.prototype.canRefine = function (
        tile,
        frameState,
        occluders
      ) {
        if (tile.level < 21) return true;
        return false;
      };

      DemoTileProvider.prototype.showTileThisFrame = function (
        tile,
        context,
        frameState,
        commandList
      ) {
        // if (!tile.data) {
        //     tile.state = Cesium.QuadtreeTileLoadState.START;
        //     return;
        // }
        if (tile.data && tile.data.geometryPrimitive)
          tile.data.geometryPrimitive.update(context, frameState, commandList);
        // tile.data.geometryPrimitive._isUpdateQuad = 1;
      };

      DemoTileProvider.prototype.computeDistanceToTile = function (
        tile,
        frameState
      ) {
        // The distance should be:
        // 1. the actual distance to the tight-fitting bounding volume, or
        // 2. a distance that is equal to or greater than the actual distance to the tight-fitting bounding volume.
        //
        // When we don't know the min/max heights for a tile, but we do know the min/max of an ancestor tile, we can
        // build a tight-fitting bounding volume horizontally, but not vertically. The min/max heights from the
        // ancestor will likely form a volume that is much bigger than it needs to be. This means that the volume may
        // be deemed to be much closer to the camera than it really is, causing us to select tiles that are too detailed.
        // Loading too-detailed tiles is super expensive, so we don't want to do that. We don't know where the child
        // tile really lies within the parent range of heights, but we _do_ know the child tile can't be any closer than
        // the ancestor height surface (min or max) that is _farthest away_ from the camera. So if we compute distance
        // based that conservative metric, we may end up loading tiles that are not detailed enough, but that's much
        // better (faster) than loading tiles that are too detailed.

        var heightSource = updateTileBoundingRegion(
          tile,
          this.terrainProvider,
          frameState
        );
        var surfaceTile = tile.data;
        var tileBoundingRegion = surfaceTile.tileBoundingRegion;

        if (heightSource === undefined) {
          // Can't find any min/max heights anywhere? Ok, let's just say the
          // tile is really far away so we'll load and render it rather than
          // refining.
          return 9999999999.0;
        } else if (surfaceTile.boundingVolumeSourceTile !== heightSource) {
          // Heights are from a new source tile, so update the bounding volume.
          surfaceTile.boundingVolumeSourceTile = heightSource;

          var rectangle = tile.rectangle;
          if (
            rectangle &&
            rectangle.width < Cesium.Math.PI_OVER_TWO + Cesium.Math.EPSILON5
          ) {
            surfaceTile.orientedBoundingBox = Cesium.OrientedBoundingBox.fromRectangle(
              tile.rectangle,
              tileBoundingRegion.minimumHeight,
              tileBoundingRegion.maximumHeight,
              tile.tilingScheme.ellipsoid,
              surfaceTile.orientedBoundingBox
            );

            surfaceTile.occludeePointInScaledSpace = computeOccludeePoint(
              this,
              surfaceTile.orientedBoundingBox.center,
              tile.rectangle,
              tileBoundingRegion.maximumHeight,
              surfaceTile.occludeePointInScaledSpace
            );
          }
        }

        var min = tileBoundingRegion.minimumHeight;
        var max = tileBoundingRegion.maximumHeight;

        if (surfaceTile.boundingVolumeSourceTile !== tile) {
          var cameraHeight = frameState.camera.positionCartographic.height;
          var distanceToMin = Math.abs(cameraHeight - min);
          var distanceToMax = Math.abs(cameraHeight - max);
          if (distanceToMin > distanceToMax) {
            tileBoundingRegion.minimumHeight = min;
            tileBoundingRegion.maximumHeight = min;
          } else {
            tileBoundingRegion.minimumHeight = max;
            tileBoundingRegion.maximumHeight = max;
          }
        }

        var result = tileBoundingRegion.distanceToCamera(frameState);

        tileBoundingRegion.minimumHeight = min;
        tileBoundingRegion.maximumHeight = max;

        return result;
      };

      function updateTileBoundingRegion(tile, terrainProvider, frameState) {
        var surfaceTile = tile.data;
        if (surfaceTile === undefined) {
          surfaceTile = tile.data = new Cesium.GlobeSurfaceTile();
        }

        if (surfaceTile.tileBoundingRegion === undefined) {
          surfaceTile.tileBoundingRegion = new Cesium.TileBoundingRegion({
            computeBoundingVolumes: false,
            rectangle: tile.rectangle,
            ellipsoid: tile.tilingScheme.ellipsoid,
            minimumHeight: minimumHeight,
            // minimumHeight: tile._minimumHeight || -100.0,
            maximumHeight: tile._maximumHeight || 0.0,
            // minimumHeight: -1000,
            // maximumHeight: 0
          });
        }
        return tile;
      }

      function clipRectangleAntimeridian(
        tileRectangle,
        cartographicLimitRectangle
      ) {
        if (cartographicLimitRectangle.west < cartographicLimitRectangle.east) {
          return cartographicLimitRectangle;
        }
        var splitRectangle = Rectangle.clone(
          cartographicLimitRectangle,
          splitCartographicLimitRectangleScratch
        );
        var tileCenter = Rectangle.center(
          tileRectangle,
          rectangleCenterScratch
        );
        if (tileCenter.longitude > 0.0) {
          splitRectangle.east = CesiumMath.PI;
        } else {
          splitRectangle.west = -CesiumMath.PI;
        }
        return splitRectangle;
      }

      function computeOccludeePoint(
        tileProvider,
        center,
        rectangle,
        height,
        result
      ) {
        var ellipsoidalOccluder = tileProvider.quadtree._occluders.ellipsoid;
        var ellipsoid = ellipsoidalOccluder.ellipsoid;

        var cornerPositions = cornerPositionsScratch;
        Cesium.Cartesian3.fromRadians(
          rectangle.west,
          rectangle.south,
          height,
          ellipsoid,
          cornerPositions[0]
        );
        Cesium.Cartesian3.fromRadians(
          rectangle.east,
          rectangle.south,
          height,
          ellipsoid,
          cornerPositions[1]
        );
        Cesium.Cartesian3.fromRadians(
          rectangle.west,
          rectangle.north,
          height,
          ellipsoid,
          cornerPositions[2]
        );
        Cesium.Cartesian3.fromRadians(
          rectangle.east,
          rectangle.north,
          height,
          ellipsoid,
          cornerPositions[3]
        );

        return ellipsoidalOccluder.computeHorizonCullingPoint(
          center,
          cornerPositions,
          result
        );
      }
      DemoTileProvider.prototype.isDestroyed = function () {
        return false;
      };
      DemoTileProvider.prototype.destroy = function () {
        return Cesium.destroyObject(this);
      };
      DemoTileProvider.prototype.updateForPick = function (frameState) {
        // Add the tile pick commands from the tiles drawn last frame.
        // var drawCommands = this._drawCommands;
        // for (var i = 0, length = this._usedDrawCommands; i < length; ++i) {
        //     frameState.commandList.push(drawCommands[i]);
        // }
      };
      // var viewer = new Cesium.Viewer('cesiumContainer');
      var viewer = new Cesium.Viewer("cesiumContainer", {
        //需要进行可视化的数据源的集合
        animation: false, //是否显示动画控件
        shouldAnimate: true,
        homeButton: false, //是否显示Home按钮
        fullscreenButton: false, //是否显示全屏按钮
        baseLayerPicker: false, //是否显示图层选择控件
        geocoder: false, //是否显示地名查找控件
        timeline: false, //是否显示时间线控件
        sceneModePicker: true, //是否显示投影方式控件
        navigationHelpButton: false, //是否显示帮助信息控件
        infoBox: false, //是否显示点击要素之后显示的信息
        requestRenderMode: true, //启用请求渲染模式
        scene3DOnly: false, //每个几何实例将只能以3D渲染以节省GPU内存
        sceneMode: 3, //初始场景模式 1 2D模式 2 2D循环模式 3 3D模式  Cesium.SceneMode
        fullscreenElement: document.body, //全屏时渲染的HTML元素 暂时没发现用处
        //天地图是官方开元的地图，不需要密钥
        imageryProvider: new Cesium.UrlTemplateImageryProvider({
          url:
            "http://mt1.google.cn/vt/lyrs=s&hl=zh-CN&x={x}&y={y}&z={z}&s=Gali",
        }),
      });

      var scene = viewer.scene;
      var primitives = scene.primitives;
      var tileProvider = new DemoTileProvider();
      var prim = new Cesium.QuadtreePrimitivezh({
        // var prim = new Cesium.QuadtreePrimitive({
        tileProvider: tileProvider,
        tileCacheSize: 100,
      });
      scene.primitivesQuadTrees.push(prim);
      scene.primitives.add(prim);
      // scene.primitives.add(tileProvider._PrimitiveCollection);

      // // 1. Draw a translucent ellipse on the surface with a checkerboard pattern
      // var instance = new Cesium.GeometryInstance({
      //     geometry: new Cesium.EllipseGeometry({
      //         center: Cesium.Cartesian3.fromDegrees(-100.0, 20.0),
      //         semiMinorAxis: 500000.0,
      //         semiMajorAxis: 1000000.0,
      //         rotation: Cesium.Math.PI_OVER_FOUR,
      //         vertexFormat: Cesium.VertexFormat.POSITION_AND_ST
      //     }),
      //     id: 'object returned when this instance is picked and to get/set per-instance attributes'
      // });
      // var c = new Cesium.Primitive({
      //     geometryInstances: instance,
      //     appearance: new Cesium.EllipsoidSurfaceAppearance({
      //         material: Cesium.Material.fromType('Checkerboard')
      //     })
      // });
      // scene.primitives.add(c);

      // var rectangleInstance = new Cesium.GeometryInstance({
      //     geometry: new Cesium.RectangleGeometry({
      //         rectangle: Cesium.Rectangle.fromDegrees(-140.0, 30.0, -100.0, 40.0),
      //         vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
      //     }),
      //     attributes: {
      //         color: new Cesium.ColorGeometryInstanceAttribute(0.0, 1.0, 1.0, 0.5)
      //     }
      // });
      // var ellipsoidInstance = new Cesium.GeometryInstance({
      //     geometry: new Cesium.EllipsoidGeometry({
      //         radii: new Cesium.Cartesian3(500000.0, 500000.0, 1000000.0),
      //         vertexFormat: Cesium.VertexFormat.POSITION_AND_NORMAL
      //     }),
      //     modelMatrix: Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
      //         Cesium.Cartesian3.fromDegrees(-95.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 500000.0), new Cesium.Matrix4()),
      //     attributes: {
      //         color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.AQUA)
      //     }
      // });

      // var c1 = new Cesium.Primitive({
      //     geometryInstances: [rectangleInstance, ellipsoidInstance],
      //     appearance: new Cesium.PerInstanceColorAppearance()
      // });
      // scene.primitives.add(c1);

      // function leftClickEvent(e) {

      //     var Viewer = viewer;
      //     var leftPickPoint_eventListener = new Cesium.ScreenSpaceEventHandler(Viewer.scene.canvas);
      //     leftPickPoint_eventListener.setInputAction(function(movement) {
      //         var pickedObject = Viewer.scene.pick(movement.position);

      //         debugger

      //     }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
      // }
    </script>
  </body>
</html>
<script src="underground.js"></script>
